/////////////////////////////////////////////////////
// File Name: rr_arbiter.v
// Author: zeping fan
// mail:   zpfan007@163.com
// Created Time: 2023年09月21日 星期四 20时36分14秒
/////////////////////////////////////////////////////

module rr_arbiter(
clk,
rst_n,
req,
grant,
grant_vld,
grant_ff,
grant_ff_vld,
switch_to_next
);

parameter   REQ_CNT     = 4;

input                   clk;
input                   rst_n;
input   [REQ_CNT-1:0]   req;
output  [REQ_CNT-1:0]   grant;
output                  grant_vld;
output  [REQ_CNT-1:0]   grant_ff;
output                  grant_ff_vld;
input                   switch_to_next;

wire    [REQ_CNT-1:0]   grant;
wire                    grant_vld;
reg     [REQ_CNT-1:0]   grant_ff;
reg                     grant_ff_vld;

wire                    no_req;
wire                    no_grant;
wire                    first_grant;
wire                    arb_trig;

assign no_req       = ~(|req);
assign no_grant     = ~(|grant_ff);
assign first_grant  = ~no_req && no_grant;
assign arb_trig     = first_grant || switch_to_next;


wire    [REQ_CNT-1:0]   req_masked;
wire    [REQ_CNT-1:0]   mask_higher_pri_reqs;
wire    [REQ_CNT-1:0]   grant_masked;
wire    [REQ_CNT-1:0]   unmask_higher_pri_reqs;
wire    [REQ_CNT-1:0]   grant_unmasked;
wire                    no_req_masked;
reg     [REQ_CNT-1:0]   pointer_reg;

//Simple priority arbitration for masked portion
assign req_masked[REQ_CNT-1:0] = req & pointer_reg;
assign mask_higher_pri_reqs[0] = 1'b0;
assign mask_higher_pri_reqs[REQ_CNT-1:1] = req_masked[REQ_CNT-2:0] | mask_higher_pri_reqs[REQ_CNT-2:0];
assign grant_masked[REQ_CNT-1:0] = req_masked[REQ_CNT-1:0] & ~mask_higher_pri_reqs[REQ_CNT-1:0];

//Simple priority arbitration for unmasked portion
assign unmask_higher_pri_reqs[0] = 1'b0;
assign unmask_higher_pri_reqs[REQ_CNT-1:1] = req[REQ_CNT-2:0] | unmask_higher_pri_reqs[REQ_CNT-2:0];
assign grant_unmasked[REQ_CNT-1:0] = req[REQ_CNT-1:0] & ~unmask_higher_pri_reqs[REQ_CNT-1:0];

//Use grant_masked if there is any there, otherwise use grant_unmasked
assign no_req_masked = ~(|req_masked);
assign grant = ({REQ_CNT{no_req_masked}} & grant_unmasked) | grant_masked;
assign grant_vld = (arb_trig && |req)? 1'b1 : 1'b0;
//pointer update
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        pointer_reg <= {REQ_CNT{1'b1}};
    else if(arb_trig)begin
        if(|req_masked)
            pointer_reg <= mask_higher_pri_reqs;
        else begin
            if(|req)
                pointer_reg <= unmask_higher_pri_reqs;
            else 
                pointer_reg <= pointer_reg;
        end
    end
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin 
        grant_ff <= {REQ_CNT{1'b0}};  
        grant_ff_vld <= 1'b0;
    end 
    else if(arb_trig)begin
        grant_ff <= grant;
        grant_ff_vld <= no_req? 1'b0 : 1'b1;
    end 
    else begin 
        grant_ff <= grant_ff;
        grant_ff_vld <= grant_ff_vld;
    end
end

endmodule




/*
reg     [REQ_CNT-1:0]   grant_base;
wire    [REQ_CNT*2-1:0] double_req;
wire    [REQ_CNT*2-1:0] double_grant;

wire                    no_req;
wire                    no_grant;
wire                    first_grant;
wire                    arb_trig;

assign no_req       = ~(|req);
assign no_grant     = ~(|grant_ff);
assign first_grant  = ~no_req && no_grant;
assign arb_trig     = first_grant || switch_to_next;


always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        grant_base[REQ_CNT-1:0] <= INIT_GRANT;
    else if(arb_trig && ~no_req)
        grant_base[REQ_CNT-1:0] <= {grant[REQ_CNT-2:0],grant[REQ_CNT-1]};
end

assign double_req[REQ_CNT*2-1:0] = {req,req};
assign double_grant[REQ_CNT*2-1:0] = double_req & (~(double_req - grant_base));
assign grant = arb_trig? (double_grant[REQ_CNT*2-1:REQ_CNT] | double_grant[REQ_CNT-1:0]) : {REQ_CNT{1'b0}};
assign grant_vld = (arb_trig && ~no_req)? 1'b1 : 1'b0;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        grant_ff <= {REQ_CNT{1'b0}};        
    else if(arb_trig)
        grant_ff <= grant;
    else 
        grant_ff <= grant_ff;
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        grant_ff_vld <= 1'b0;
    else if(arb_trig)
        grant_ff_vld <= no_req? 1'b0 : 1'b1;
end
*/




